package sk.tuke.serviceImpl;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.jws.WebMethod;
import javax.ws.rs.core.Response;

import sk.tuke.domain.Diagnose;
import sk.tuke.domain.Drug;
import sk.tuke.domain.HealthCard;
import sk.tuke.domain.MedicalNote;
import sk.tuke.domain.MedicalRecord;
import sk.tuke.domain.Status;
import sk.tuke.domain.Symptom;
import sk.tuke.domain.IO.healthcardManagemet.CreateHealthcardInput;
import sk.tuke.domain.IO.healthcardManagemet.CreateMedicalRecordInput;
import sk.tuke.domain.IO.healthcardManagemet.CreateMedicalRecordOutput;
import sk.tuke.domain.IO.healthcardManagemet.GetHealthCardInput;
import sk.tuke.domain.IO.healthcardManagemet.GetHealthCardOutput;
import sk.tuke.domain.IO.healthcardManagemet.GetMedicalRecordInput;
import sk.tuke.domain.IO.healthcardManagemet.GetMedicalRecordOutput;
import sk.tuke.persistance.DiagnosePo;
import sk.tuke.persistance.DiseasePo;
import sk.tuke.persistance.DrugPo;
import sk.tuke.persistance.HealthCardPo;
import sk.tuke.persistance.MedicalNotePo;
import sk.tuke.persistance.MedicalRecordPo;
import sk.tuke.persistance.SymptomPo;
import sk.tuke.serviceDao.AbstractDao;
import sk.tuke.serviceDao.DiagnoseManagementDao;
import sk.tuke.serviceDao.HealthcardManagementDao;
import sk.tuke.serviceInterface.HealthcardManagementService;
import sk.tuke.utils.MapperDomainToPo;
import sk.tuke.utils.MapperPOtoDomain;
import sk.tuke.utils.Utils;

public class HealthcardManagementServiceImpl extends CommonService implements HealthcardManagementService {

	private HealthcardManagementDao healthcardManagementDao;

	private DiagnoseManagementDao diagnoseManagementDao;

	private AbstractDao abstractDao;

	private MapperDomainToPo mapperDomainToPo;

	private MapperPOtoDomain mapperPoToDomain;

	public HealthcardManagementDao getHealthcardManagementDao() {
		return healthcardManagementDao;
	}

	public void setHealthcardManagementDao(HealthcardManagementDao healthcardManagementDao) {
		this.healthcardManagementDao = healthcardManagementDao;
	}

	public void setDiagnoseManagementDao(DiagnoseManagementDao diagnoseManagementDao) {
		this.diagnoseManagementDao = diagnoseManagementDao;
	}

	public DiagnoseManagementDao getDiagnoseManagementDao() {
		return diagnoseManagementDao;
	}

	public MapperDomainToPo getMapperDomainToPo() {
		return mapperDomainToPo;
	}

	public void setMapperDomainToPo(MapperDomainToPo mapperDomainToPo) {
		this.mapperDomainToPo = mapperDomainToPo;
	}

	public MapperPOtoDomain getMapperPoToDomain() {
		return mapperPoToDomain;
	}

	public void setMapperPoToDomain(MapperPOtoDomain mapperPoToDomain) {
		this.mapperPoToDomain = mapperPoToDomain;
	}

	public void setAbstractDao(AbstractDao abstractDao) {
		this.abstractDao = abstractDao;
	}

	public AbstractDao getAbstractDao() {
		return abstractDao;
	}

	public Response createHealthcard(CreateHealthcardInput createHealthcardInput) throws Throwable {
		// TODO Auto-generated method stub
		return null;
	}

	public Response createMedicalRecord(CreateMedicalRecordInput createMedicalRecordInput) throws Throwable {
		try {
			Utils.checkObjectToNull(new String[] { "createMedicalRecordInput" }, createMedicalRecordInput);
			MedicalRecord medicalRecord = createMedicalRecordInput.getMedicalRecord();
			Utils.checkObjectToNull(new String[] { "medicalRecord" }, medicalRecord);
			Diagnose diagnose = medicalRecord.getDiagnose();
			Status status = medicalRecord.getStatus();
			List<MedicalNote> medicalNotes = medicalRecord.getMedicalNotes();
			Utils.checkObjectToNull(new String[] { "diagnose", "status", "name", "number", "date", "healthCardNumber" }, diagnose, status,
					medicalRecord.getName(), medicalRecord.getNumber(), medicalRecord.getDate(), medicalRecord.getHealthCardNumber());
			Utils.checkObjectToNull(new String[] { "drugNames" }, diagnose.getDrugs());

			Set<MedicalNotePo> medicalNotePos = new TreeSet<MedicalNotePo>();
			for (MedicalNote medicalNote : medicalNotes) {
				medicalNotePos.add(healthcardManagementDao.createMedicalNote(medicalNote.getName(), medicalNote.getDescription()));
			}
			
			List<String> drugNames = new ArrayList<String>();
			for (Drug drug : diagnose.getDrugs()) {
				drugNames.add(drug.getName());
			}
			
			List<String> symptomNames = new ArrayList<String>();
			for (Symptom symptom : diagnose.getSymptoms()) {
				symptomNames.add(symptom.getName());
			}

			HealthCardPo healthCardPo = abstractDao.findEntityByNumber(HealthCardPo.class, medicalRecord.getHealthCardNumber());

			List<DrugPo> drugPos = abstractDao.findEntitiesByNames(DrugPo.class, drugNames);

			DiseasePo diseasePo = abstractDao.findEntityByName(DiseasePo.class, diagnose.getDisease().getName());

			List<SymptomPo> symptomPos = abstractDao.findEntitiesByNames(SymptomPo.class, symptomNames);

			DiagnosePo diagnosePo = diagnoseManagementDao.createDiagnose(diagnose.getNumber(), diagnose.getName(), diagnose.getDescription(), Utils.convertListToSet(symptomPos),
					diseasePo, Utils.convertListToSet(drugPos));

			MedicalRecordPo medicalRecordPo = healthcardManagementDao.createMedicalRecord(medicalRecord.getNumber(), healthCardPo, medicalRecord.getName(),
					medicalRecord.getDate(), diagnosePo, status.name(), medicalNotePos);

			CreateMedicalRecordOutput result = new CreateMedicalRecordOutput();
			result.setMedicalRecord(mapperPoToDomain.mapMedicalRecordPoToMedicalRecord(medicalRecordPo));
			return Response.status(Response.Status.OK).entity(result).build();
		} catch (Exception e) {
			return handleException(CreateMedicalRecordOutput.class, e, Response.Status.BAD_REQUEST);
		}
	}

	@WebMethod
	public Response getHealthCard(GetHealthCardInput getHealthCardInput) throws Throwable {
		try {
			Utils.checkObjectToNull(new String[] { "getHealthCardInput" }, getHealthCardInput);
			HealthCardPo healthCardPo = healthcardManagementDao.getHealthCard(getHealthCardInput.getNumber());
			if (healthCardPo == null) {
				throw new Exception("Any healthcard with defined search parameters does not exists in the database.");
			}
			HealthCard healthCard = mapperPoToDomain.mapHealthCardPoToHealthCard(healthCardPo);
			GetHealthCardOutput result = new GetHealthCardOutput();
			result.setHealthCard(healthCard);
			return Response.status(Response.Status.OK).entity(result).build();
		} catch (Exception e) {
			return handleException(GetHealthCardOutput.class, e, Response.Status.BAD_REQUEST);
		}
	}

	@WebMethod
	public Response getMedicalRecord(GetMedicalRecordInput getMedicalRecordInput) throws Throwable {
		try {
			Utils.checkObjectToNull(new String[] { "getMedicalRecordInput" }, getMedicalRecordInput);
			MedicalRecordPo medicalRecordPo = healthcardManagementDao.getMedicalRecord(getMedicalRecordInput.getNumber());
			if (medicalRecordPo == null) {
				throw new Exception("Any record with defined search parameters does not exists in the database.");
			}
			MedicalRecord medicalRecord = mapperPoToDomain.mapMedicalRecordPoToMedicalRecord(medicalRecordPo);
			GetMedicalRecordOutput result = new GetMedicalRecordOutput();
			result.setMedicalRecord(medicalRecord);
			return Response.status(Response.Status.OK).entity(result).build();
		} catch (Exception e) {
			return handleException(GetMedicalRecordOutput.class, e, Response.Status.BAD_REQUEST);
		}
	}

}